package com.anji.plus.gaea.oss.ossbuilder.builders;

import org.apache.commons.io.IOUtils;

import java.io.InputStream;
import java.util.List;

import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import com.anji.plus.gaea.oss.config.OSSProperties;
import com.anji.plus.gaea.oss.exceptions.GaeaOSSException;
import com.anji.plus.gaea.oss.exceptions.GaeaOSSExceptionBuilder;
import com.anji.plus.gaea.oss.ossbuilder.GaeaOSSTemplate;
import com.obs.services.ObsClient;
import com.obs.services.model.DeleteObjectsRequest;
import com.obs.services.model.DeleteObjectsResult;
import com.obs.services.model.ListVersionsRequest;
import com.obs.services.model.ListVersionsResult;
import com.obs.services.model.ObsObject;
import com.obs.services.model.VersionOrDeleteMarker;

/**
 * https://support.huaweicloud.com/sdk-java-devg-obs/obs_21_0603.html
 *
 * @author WongBin
 * @date 2023/8/24
 */
public class HuaweiOBSClient implements GaeaOSSTemplate {
    // 存储桶名称
    private String bucketName;
    // 允许的文件后缀 白名单
    private String fileTypeWhiteList;
    private ObsClient ossClient;

    public HuaweiOBSClient(OSSProperties properties) {
        this.init(properties);
    }

    @Override
    public void init(OSSProperties config) {
        // Endpoint以北京四为例，其他地区请按实际情况填写。
        /*String endPoint = "https://obs.cn-north-4.myhuaweicloud.com";
        String ak = "*** Provide your Access Key ***";
        String sk = "*** Provide your Secret Key ***";*/
        // 创建ObsClient实例
        ossClient = new ObsClient(config.getHuaweiObs().getAccessKey(),
                config.getHuaweiObs().getSecretKey(), config.getHuaweiObs().getUrl());
        this.bucketName = config.getHuaweiObs().getBucketName();
        this.fileTypeWhiteList = config.getFileTypeWhiteList();

        // localfile2 为待上传的本地文件路径，需要指定到具体的文件名
        /*PutObjectRequest request = new PutObjectRequest();
        request.setBucketName("bucketname");
        request.setObjectKey("objectkey2");
        request.setFile(new File("localfile2"));
        obsClient.putObject(request);*/
    }

    @Override
    public void close() {
        if(ossClient!=null){
            try {
                ossClient.close();
            }catch (Exception ex){
                logger.error("close-client-err:{}",ex);
            }
            logger.info("shutdown-oss-client");
        }
    }

    @Override
    public String getFileTypeWhiteList() {
        return fileTypeWhiteList;
    }

    /**
     * 文件上传，输入参数为InputStream
     *
     * @param file
     * @return
     */
    @Override
    public String uploadFileByInputStream(MultipartFile file, String fileObjectName)
            throws GaeaOSSException {
        //判断文件后缀名是否在白名单中，如果不在报异常，中止文件保存
        checkFileSuffixName(file);
        InputStream fileInputStream = null;
        try {
            ossClient.putObject(this.bucketName, fileObjectName, file.getInputStream());
        } catch (Exception e) {
            logger.error("save file error:", e);
            throw GaeaOSSExceptionBuilder.build("save file error", e);
        } finally {
            try {
                if (fileInputStream != null) {
                    fileInputStream.close();
                }
            } catch (Exception e) {
                logger.error("close InputStream error:", e);
            }
        }
        return fileObjectName;
    }

    /**
     * 根据fileUUid下载文件
     *
     * @param fileObjectName
     * @return
     */
    @Override
    public byte[] downloadFile(String fileObjectName) throws GaeaOSSException {
        byte[] fileBytes = null;
        InputStream inputStream = null;
        try {
            ObsObject obsObject = ossClient.getObject(this.bucketName, fileObjectName);
            if (obsObject == null) {
                logger.error("file {} not exist in minio store ", fileObjectName);
                throw GaeaOSSExceptionBuilder.build("file not exist,objectName="+ fileObjectName);
            }
            inputStream = obsObject.getObjectContent();
            fileBytes = IOUtils.toByteArray(inputStream);
        } catch (Exception e) {
            logger.error("read file error:", e);
            throw GaeaOSSExceptionBuilder.build("read file error, objectName="+ fileObjectName);
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (Exception e) {

                }
            }
        }
        return fileBytes;
    }

    @Override
    public void deleteFile(String fileObjectName) {
        try{
            ossClient.deleteObject(this.bucketName, fileObjectName);
        }catch (Exception e){
            logger.warn("delete file fail, bucket={}, file={}", this.bucketName, fileObjectName);
        }
    }

    // https://support.huaweicloud.com/sdk-java-devg-obs/obs_21_0804.html
    @Override
    public void deleteFiles(List<String> fileObjectNames) {
        if(CollectionUtils.isEmpty(fileObjectNames)){
            return;
        }
        fileObjectNames.stream().forEach(this::deleteFile);
        /*try{

            //ossClient.deleteObjects(this.bucketName, fileObjectNames);
            ListVersionsRequest request = new ListVersionsRequest(bucketName);
            // 每次批量删除100个对象
            request.setMaxKeys(100);
            //request.set
            ListVersionsResult result;
            do {
                result = ossClient.listVersions(request);

                DeleteObjectsRequest deleteRequest = new DeleteObjectsRequest(bucketName);
                deleteRequest.setQuiet(true); // 注意此demo默认是详细模式，如果要使用简单模式，请添加本行代码
                for(VersionOrDeleteMarker v  : result.getVersions()) {
                    deleteRequest.addKeyAndVersion(v.getKey(), v.getVersionId());
                }

                DeleteObjectsResult deleteResult = ossClient.deleteObjects(deleteRequest);
                // 获取删除成功的对象
                logger.info("deleted-obj:{}",deleteResult.getDeletedObjectResults());
                // 获取删除失败的对象
                logger.info("delete-err-obj:{}",deleteResult.getErrorResults());

                request.setKeyMarker(result.getNextKeyMarker());
                // 如果没有开启多版本对象，就不需要设置VersionIdMarker
                request.setVersionIdMarker(result.getNextVersionIdMarker());
            }while(result.isTruncated());
        }catch (Exception e){
            logger.warn("delete file fail, bucket={}, file={}", this.bucketName, fileObjectNames.toString());
        }*/
    }
}
